package com.zycoin.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhongyicheng
 * create date 2018/1/11.
 */
public class Handler implements Runner {
    SocketChannel socketChannel;
    SelectionKey sk;
    ByteBuffer input = ByteBuffer.allocate(1024);
    ByteBuffer output = ByteBuffer.allocate(1024);
    static final int READING = 0, PROCESSING = 3, SENDING = 1, END = 2;
    int state = READING;
    byte end = 13; //换行符 \n

    private static final ExecutorService executor = Executors.newCachedThreadPool();
    Lock lock = new ReentrantLock();

    public Handler(Selector selector, SocketChannel sc) throws IOException {
        this.socketChannel = sc;
        sc.configureBlocking(false);
        /*在Acceptor中初始化Dispatch时，此selector调用select()方法已阻塞，需要唤醒才能进行注册新的channel的读事件*/
        selector.wakeup();
        sk = this.socketChannel.register(selector, SelectionKey.OP_READ);
        sk.attach(this);
    }

    public void run() {
        lock.lock();
        try {
            if (state == READING) read();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    void read() throws IOException {
        socketChannel.read(input);
        input.clear();
        List<Byte> bytes = new ArrayList<Byte>();
        Byte tmpByte;
        while ((socketChannel.read(input)) != -1) {
            input.flip();
            boolean flag = false;
            while (input.hasRemaining()) {
                tmpByte = input.get();
                if (end == tmpByte) {
                    flag = true;
                    bytes.add(tmpByte);
                    break;
                }
                bytes.add(tmpByte);
            }
            input.clear();
            if (flag)
                break;

        }
        state = PROCESSING;
        Byte[] a = new Byte[bytes.size()];
        a = bytes.toArray(a);
        byte [] b = new byte[a.length];
        for(int i=0;i<a.length;i++)
            b[i]=a[i];
        String req = new String(b,"UTF-8");
        executor.execute(new Process(req, this));
    }

    void send() throws IOException {
        socketChannel.write(output);
        /*重新注册读事件*/
//        sk.attach(this);
//        sk.interestOps(SelectionKey.OP_READ);

        /*关闭连接*/
        state = END;
        sk.cancel();
        try {
            socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void process(String rtnMsg) {
        sk.interestOps(SelectionKey.OP_WRITE);
        byte[] req = rtnMsg.getBytes();
        output.clear();
        output = ByteBuffer.allocate(req.length);
        output.put(req);
        output.flip();
        try {
            send();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
